﻿//
// Author: rgy
// Date: 2016-03-18 09:23:00
//

using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using SLua;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// ScrollRect
/// </summary>
public class SoarDScrollRect : CanvasModeBehaviour, ISoarDScroll, IPointerDownHandler, IPointerUpHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
{

    /// <summary>
    /// 释放方向
    /// </summary>
    public enum ReleaseDirect
    {
        None,
        DownToUp,
        UpToDown
    }

    /// <summary>
    /// 刷新类型
    /// </summary>
    public enum EndReleaseType
    {
        Hide,
        ShowEndHint,
    }

    private bool _init;
    protected bool m_IsEnable;
    protected float _releaseBorder = 50;                //释放边缘距离
    protected string ReleaseKey = "common_text_084";    //放开刷新Key
    protected string SwipeUpKey = "common_text_089";    //上拉Key
    protected string EndOfHistoryKey = "common_text_085";  //滑动到最后(聊天，消息专用)
    protected bool _endOfRelease = false;               //刷新结束
    public ReleaseDirect releaseDirect;                 //放开刷新功能
    public EndReleaseType endRelease;                   //结束刷新后显示
    public RectTransform viewPort;                      //显示
    public RectTransform content;                       //内容
    public Text releaseText;                            //释放文本
    protected Text _release;
    public bool horzontal;                              //水平移动
    public bool vertical;                               //垂直移动
    public float clampedLength;                         //夹的距离

    protected Vector2 _dragPosition;                    //Drag记录点
    protected Vector2 m_ContentStartPosition;           //起始点
    protected bool _pointerDown;                        //鼠标点下
    protected bool m_Dragging;                          //滑动中

    //---------------惯性------------
    protected Vector2 _moveDistance;                    //移动距离
    protected Vector2 InertiaDestPoint                  //惯性目标点
    {
        get
        {
            Vector2 targetPos = _moveDistance * InertiaStep;
            if (targetPos.y > ViewHeight / 2)
            {
                targetPos.y = ViewHeight / 2;
            }
            if (targetPos.y < -ViewHeight / 2)
            {
                targetPos.y = -ViewHeight / 2;
            }
            return targetPos;
        }
    }
    protected float InertiaStep = 5f;                     //惯性距离倍数
    protected float InertiaSpeed = 5f;                   //惯性速度
    protected float OutInertiaSpeed = 30f;                  //出界时惯性速度
    protected float _nowInertiaSpeed;                 //惯性速度
    protected Vector2 lastPoint = Vector2.zero;           //最后的点
    protected Vector2 firstPoint = Vector2.zero;          //最先的点

    protected float ElasticTime = 0.2f;                   //弹性(多少时间归位)
    protected float MoveTime = 0.3f;                      //移动时间

    [Serializable]
    public class SoarDScrollRectEvent : UnityEvent { }
    [SerializeField]
    private SoarDScrollRectEvent m_OnValueChanged = new SoarDScrollRectEvent();
    public SoarDScrollRectEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
    [SerializeField]
    private SoarDScrollRectEvent m_DragEnd = new SoarDScrollRectEvent();
    public SoarDScrollRectEvent onDragEnd { get { return m_DragEnd; } set { m_DragEnd = value; } }
    [SerializeField]
    private SoarDScrollRectEvent m_SlideEnd = new SoarDScrollRectEvent();
    public SoarDScrollRectEvent onSlideEnd { get { return m_SlideEnd; } set { m_SlideEnd = value; } }

    [HideInInspector]
    public UnityAction onPressDown;

    protected LTDescr _ltDescrHorzontal;                  //水平归位动画。
    protected LTDescr _ltDescrVertical;                   //垂直归位动画
    protected LTDescr _ltDescrMove;                       //移动动画

    /// <summary>
    /// Content宽度
    /// </summary>
	protected float ContentWidth
    {
        get { return content.rect.width; }
    }

    /// <summary>
    /// ViewPort宽度
    /// </summary>
	protected float ViewWidth
    {
        get { return viewPort.rect.width; }
    }

    /// <summary>
    /// Content与ViewPort宽度差
    /// </summary>
	protected float ViewWidthDis
    {
        get { return (ContentWidth - ViewWidth); }
    }

    /// <summary>
    /// Content高度
    /// </summary>
	protected float ContentHeight
    {
        get { return content.rect.height; }
    }

    /// <summary>
    /// ViewPort高度
    /// </summary>
	protected float ViewHeight
    {
        get { return viewPort.rect.height; }
    }

    /// <summary>
    /// Content与ViewPort高度差
    /// </summary>
	protected float ViewHeightDis
    {
        get { return (ContentHeight - ViewHeight); }
    }

    /// <summary>
    /// Content的坐标
    /// </summary>
    protected Vector2 ContentPosition
    {
        get { return content.anchoredPosition; }
        set { content.anchoredPosition = value; }
    }

    /// <summary>
    /// 是否按下
    /// </summary>
    public bool IsDrag
    {
        get { return m_Dragging; }
    }

    //--------------------- 无限循环滚动 --------------------------
    [HideInInspector]
    public bool useLoop;                                //启动
    [HideInInspector]
    public float cell_x;                                //格子宽度
    [HideInInspector]
    public float cell_y;                                //格子高度
    [HideInInspector]
    public int loopCol;                                 //列数
    [HideInInspector]
    public int loopRow;                                 //行数
    [HideInInspector]
    public int loopMax;                                 //显示最大值
    [HideInInspector]
    public float topDistance;                           //与上方距离

    protected int _loopIndex;                             //标记位

    [HideInInspector]
    public UnityAction<int> onLoopFront;
    [HideInInspector]
    public UnityAction<int> onLoopBack;
    [HideInInspector]
    public UnityAction onReleaseRefrush;
    [HideInInspector]
    public UnityAction onScrollToStart;

    protected List<RectTransform> _tfLoops;                //

    protected LuaTable _l;

    protected override void Start()
    {
        base.Start();
        Init();
    }

    protected override void OnEnable()
    {
        base.OnEnable();
        m_IsEnable = true;
    }

    protected override void OnDisable()
    {
        base.OnDisable();
        m_IsEnable = false;
        isInertia = false;
    }

    protected override void OnCanvasHierarchyChanged()
    {
        base.OnCanvasHierarchyChanged();
        bool isShow = CheckIsShow();
        if (isShow)
        {
            m_IsEnable = true;
        }
        else
        {
            m_IsEnable = false;
            isInertia = false;
        }
    }

    private void Init()
    {
        if (_init) return;
        if (releaseDirect == ReleaseDirect.None) return;
        if (releaseText == null)
        {
            Debuger.LogError("释放刷新找不到Text");
            return;
        }
        ResetContentHeight();
        MoveDistance(Vector2.zero);
        RectTransform rt = releaseText.rectTransform;
        if (releaseDirect == ReleaseDirect.DownToUp)
        {
            rt.anchorMin = new Vector2(0, 0);
            rt.anchorMax = new Vector2(1, 0);
            rt.pivot = new Vector2(0.5f, 0);
        }
        else if (releaseDirect == ReleaseDirect.UpToDown)
        {
            rt.anchorMin = new Vector2(0, 1);
            rt.anchorMax = new Vector2(1, 1);
            rt.pivot = new Vector2(0.5f, 1);
        }
        rt.anchoredPosition3D = Vector3.zero;

        releaseText.text = LuaManager.Instance.CallFunc(LuaEventDefine.GET_LANG, SwipeUpKey).ToString();

        _init = true;
    }

    /// <summary>
    /// 缓存行数
    /// </summary>
    public int CacheRow
    {
        get
        {
            int count = 0;
            if (vertical)
            {
                count = (int)(ViewHeight / cell_y / 1.5f);
            }
            else
            {
                count = (int)(ViewWidth / cell_x / 1.5f);
            }
            return count > 0 ? count : 1;
        }
    }

    /// <summary>
    /// 设置刷新开始
    /// </summary>
    public void SetBeginRelease()
    {
        _endOfRelease = false;
        if (releaseText == null) return;
        if (endRelease == EndReleaseType.Hide || endRelease == EndReleaseType.ShowEndHint)
        {
            releaseText.gameObject.SetActive(true);
            _release = releaseText;
        }
    }

    /// <summary>
    /// 设置刷新结束
    /// </summary>
    public void SetEndRelease()
    {
        _endOfRelease = true;
        if (releaseText == null) return;
        if (endRelease == EndReleaseType.Hide)
        {
            releaseText.gameObject.SetActive(false);
            _release = null;
        }
        else if (endRelease == EndReleaseType.ShowEndHint && _release != null)
        {
            _release.text = LuaManager.Instance.CallFunc(LuaEventDefine.GET_LANG, EndOfHistoryKey).ToString();
        }
    }

    /// <summary>
    /// 设置Content坐标
    /// </summary>
    /// <param name="position"></param>
    public void SetContentPosition(Vector2 position)
    {
        ContentPosition = position;
    }

    /// <summary>
    /// 获取Content坐标
    /// </summary>
    /// <param name="position"></param>
    /// <returns></returns>
    public Vector2 GetContentPosition()
    {
        return ContentPosition;
    }

    /// <summary>
    /// 重置Content高度
    /// </summary>
    public void ResetContentHeight()
    {
        content.sizeDelta = new Vector2(content.sizeDelta.x, viewPort.rect.height);
    }

    /// <summary>
    /// 设置Content高度
    /// </summary>
    /// <param name="height"></param>
    public void SetContentHeight(float height)
    {
        Init();
        if (_release == null)
        {
            content.sizeDelta = new Vector2(content.sizeDelta.x, height);
            return;
        }
        content.sizeDelta = new Vector2(content.sizeDelta.x, height + _release.rectTransform.sizeDelta.y);
    }

    /// <summary>
    /// 获取Content高度
    /// </summary>
    public float GetContentHeight()
    {
        if (_release == null)
        {
            return content.sizeDelta.y;

        }
        return content.sizeDelta.y - _release.rectTransform.sizeDelta.y;
    }

    /// <summary>
    /// 点下
    /// </summary>
    /// <param name="eventData"></param>
    public void OnPointerDown(PointerEventData eventData)
    {
        Clean();
        _pointerDown = true;

        if (onPressDown != null)
        {
            onPressDown.Invoke();
        }
    }

    /// <summary>
    /// 放开
    /// </summary>
    /// <param name="eventData"></param>
    public void OnPointerUp(PointerEventData eventData)
    {
        if (!_pointerDown) return;
        TweenBack();
        _pointerDown = false;
    }

    /// <summary>
    /// 开始Drag
    /// </summary>
    /// <param name="eventData"></param>
    public void OnBeginDrag(PointerEventData eventData)
    {
        Clean();
        _dragPosition = eventData.position;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(viewPort, eventData.position, eventData.pressEventCamera, out _dragPosition);
        m_ContentStartPosition = ContentPosition;
        _pointerDown = false;
        m_Dragging = true;
    }

    /// <summary>
    /// Drag
    /// </summary>
    /// <param name="eventData"></param>
    public void OnDrag(PointerEventData eventData)
    {
        Vector2 localCursor;
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewPort, eventData.position, eventData.pressEventCamera, out localCursor))
            return;
        var pointerDelta = localCursor - _dragPosition;
        Vector2 position = m_ContentStartPosition + pointerDelta;
        _moveDistance = position - ContentPosition;
        //        if (!horzontal)
        //        {
        //            _moveDistance.x = 0;
        //        }
        //        if (!vertical)
        //        {
        //            _moveDistance.y = 0;
        //        }
        MoveDistance(_moveDistance);
    }

    /// <summary>
    /// Drag结束
    /// </summary>
    /// <param name="eventData"></param>
    public void OnEndDrag(PointerEventData eventData)
    {
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (vertical)
        {
            if (max.y < m_ViewBounds.max.y || min.y > m_ViewBounds.min.y)
            {
                _nowInertiaSpeed = OutInertiaSpeed;
            }
            else
            {
                _nowInertiaSpeed = InertiaSpeed;
            }
        }

        if (horzontal)
        {
            if (min.x > m_ViewBounds.min.x || max.x < m_ViewBounds.max.x)
            {
                _nowInertiaSpeed = OutInertiaSpeed;
            }
            else
            {
                _nowInertiaSpeed = InertiaSpeed;
            }
        }
        lastPoint = Vector2.zero;
        firstPoint = Vector2.zero;
        isInertia = true;
        m_Dragging = false;

        if (onDragEnd != null)
        {
            onDragEnd.Invoke();
        }
    }

    /// <summary>
    /// 移动
    /// </summary>
    /// <param name="delta"></param>
	public bool MoveDistance(Vector2 delta)
    {
        UpdateBounds();
        bool border = false;
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (horzontal)
        {
            delta.y = 0;
            if (min.x + delta.x > m_ViewBounds.min.x + clampedLength)
            {
                border = true;
            }
            else if (ViewWidth > ContentWidth)
            {
                if (min.x + delta.x < m_ViewBounds.min.x - clampedLength)
                {
                    border = true;
                }
            }
            else if (max.x + delta.x < m_ViewBounds.max.x - clampedLength)
            {
                border = true;
            }
        }
        if (vertical)
        {
            delta.x = 0;
            if (max.y + delta.y < m_ViewBounds.max.y - clampedLength)
            {
                border = true;
            }
            else if (ViewHeight > ContentHeight)
            {
                if (max.y + delta.y > m_ViewBounds.max.y + clampedLength)
                {
                    border = true;
                }
            }
            else if (min.y + delta.y > m_ViewBounds.min.y + clampedLength)
            {
                border = true;
            }

            //------------ 有刷新功能 --------------
            if (_release != null)
            {
                //_endOfRelease
                switch (releaseDirect)
                {
                    case ReleaseDirect.UpToDown:
                        _release.text =
                            LuaManager.Instance.CallFunc(LuaEventDefine.GET_LANG,
                                max.y + delta.y < m_ViewBounds.max.y - _releaseBorder
                                    ? _endOfRelease ? EndOfHistoryKey : ReleaseKey
                                    : SwipeUpKey).ToString();
                        break;
                    case ReleaseDirect.DownToUp:
                        _release.text = LuaManager.Instance.CallFunc(LuaEventDefine.GET_LANG, min.y + delta.y > m_ViewBounds.min.y + _releaseBorder ? ReleaseKey : SwipeUpKey).ToString();
                        break;
                }
            }
        }

        Vector2 position = ContentPosition + delta;
        delta = CalculateOffset(delta);
        position += delta;
        if (delta.x != 0)
            position.x = position.x - RubberDelta(delta.x, m_ViewBounds.size.x);
        if (delta.y != 0)
            position.y = position.y - RubberDelta(delta.y, m_ViewBounds.size.y);
        ContentPosition = position;
        ResetLoopPosition();
        if (onValueChanged != null)
        {
            onValueChanged.Invoke();
        }
        return border;
    }


    private Vector2 CalculateOffset(Vector2 delta)
    {
        Vector2 offset = Vector2.zero;
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;

        if (horzontal)
        {
            min.x += delta.x;
            max.x += delta.x;
            if (min.x > m_ViewBounds.min.x)
                offset.x = m_ViewBounds.min.x - min.x;
            else if (max.x < m_ViewBounds.max.x)
                offset.x = m_ViewBounds.max.x - max.x;
        }

        if (vertical)
        {
            min.y += delta.y;
            max.y += delta.y;
            if (max.y < m_ViewBounds.max.y)
                offset.y = m_ViewBounds.max.y - max.y;
            else if (min.y > m_ViewBounds.min.y)
                offset.y = m_ViewBounds.min.y - min.y;
        }

        return offset;
    }

    private static float RubberDelta(float overStretching, float viewSize)
    {
        return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching);
    }

    protected Bounds m_ContentBounds;
    protected Bounds m_ViewBounds;
    private void UpdateBounds()
    {
        m_ViewBounds = new Bounds(viewPort.rect.center, viewPort.rect.size);
        m_ContentBounds = GetBounds();
        Vector3 contentSize = m_ContentBounds.size;
        Vector3 contentPos = m_ContentBounds.center;
        Vector3 excess = m_ViewBounds.size - contentSize;
        if (excess.x > 0)
        {
            contentPos.x -= excess.x * (content.pivot.x - 0.5f);
            contentSize.x = m_ViewBounds.size.x;
        }
        if (excess.y > 0)
        {
            contentPos.y -= excess.y * (content.pivot.y - 0.5f);
            contentSize.y = m_ViewBounds.size.y;
        }

        m_ContentBounds.size = contentSize;
        m_ContentBounds.center = contentPos;
    }

    private readonly Vector3[] m_Corners = new Vector3[4];
    public Bounds GetBounds()
    {
        var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
        var toLocal = viewPort.worldToLocalMatrix;
        content.GetWorldCorners(m_Corners);
        for (int j = 0; j < 4; j++)
        {
            Vector3 v = toLocal.MultiplyPoint3x4(m_Corners[j]);
            vMin = Vector3.Min(v, vMin);
            vMax = Vector3.Max(v, vMax);
        }
        var bounds = new Bounds(vMin, Vector3.zero);
        bounds.Encapsulate(vMax);
        return bounds;
    }

    /// <summary>
    /// 返回归位的Tween动画
    /// </summary>
    public void TweenBack()
    {
        //if (clampedLength <= 0.1f) return;
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (horzontal)
        {
            if (min.x > m_ViewBounds.min.x)
            {
                float distance = m_ViewBounds.min.x - min.x + ContentPosition.x;
                _ltDescrHorzontal = LeanTween.moveX(content, distance, ElasticTime);
                if (onSlideEnd != null)
                {
                    onSlideEnd.Invoke();
                }
            }
            else if (ViewWidth > ContentWidth)
            {
                if (min.x < m_ViewBounds.min.x)
                {
                    float distance = m_ViewBounds.min.x - min.x + ContentPosition.x;
                    _ltDescrHorzontal = LeanTween.moveX(content, distance, ElasticTime);
                    if (onSlideEnd != null)
                    {
                        onSlideEnd.Invoke();
                    }
                }
            }
            else if (max.x < m_ViewBounds.max.x)
            {
                float distance = m_ViewBounds.max.x - max.x + ContentPosition.x;
                _ltDescrHorzontal = LeanTween.moveX(content, distance, ElasticTime);
                if (onSlideEnd != null)
                {
                    onSlideEnd.Invoke();
                }
            }
        }
        if (vertical)
        {
            //---------- 刷新 ------------
            bool needRefrush = CheckRefrush();
            if (needRefrush)
            {
                _release.text = LuaManager.Instance.CallFunc(LuaEventDefine.GET_LANG, SwipeUpKey).ToString();
            }

            if (max.y < m_ViewBounds.max.y)
            {
                float distance = m_ViewBounds.max.y - max.y + ContentPosition.y;
                _ltDescrVertical = LeanTween.moveY(content, distance, ElasticTime);
                if (onSlideEnd != null)
                {
                    onSlideEnd.Invoke();
                }
            }
            else if (ViewHeight > ContentHeight)
            {
                if (max.y > m_ViewBounds.max.y)
                {
                    float distance = m_ViewBounds.max.y - max.y + ContentPosition.y;
                    _ltDescrVertical = LeanTween.moveY(content, distance, ElasticTime);
                    if (onSlideEnd != null)
                    {
                        onSlideEnd.Invoke();
                    }
                }
            }
            else if (min.y > m_ViewBounds.min.y)
            {
                float distance = m_ViewBounds.min.y - min.y + ContentPosition.y;
                _ltDescrVertical = LeanTween.moveY(content, distance, ElasticTime);
                if (onSlideEnd != null)
                {
                    onSlideEnd.Invoke();
                }
            }
            else
            {
                return;
            }
            if (!needRefrush) return;
            _ltDescrVertical.setOnComplete(delegate ()
            {
                if (onReleaseRefrush != null)
                {
                    onReleaseRefrush.Invoke();
                    MoveDistance(Vector2.zero);
                }
            });
        }
    }

    /// <summary>
    /// 检测是否需要刷新
    /// </summary>
    /// <returns></returns>
    public bool CheckRefrush()
    {
        if (_endOfRelease) return false;
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        switch (releaseDirect)
        {
            case ReleaseDirect.UpToDown:

                if (max.y < m_ViewBounds.max.y - _releaseBorder)
                {
                    return true;
                }
                break;
            case ReleaseDirect.DownToUp:
                if (min.y > m_ViewBounds.min.y + _releaseBorder)
                {
                    return true;
                }
                break;
        }
        return false;
    }

    /// <summary>
    /// 坐标移动
    /// </summary>
    /// <param name="position"></param>
    public void Move(Vector2 position)
    {
        Clean();
        _ltDescrMove = LeanTween.move(content, position, MoveTime);
    }

    /// <summary>
    /// X坐标移动
    /// </summary>
    /// <param name="posX"></param>
    public void MoveX(float posX)
    {
        Clean();
        if (posX < -ViewWidthDis)
        {
            posX = -ViewWidthDis;
        }
        _ltDescrMove = LeanTween.moveX(content, posX, MoveTime);
    }

    /// <summary>
    /// Y坐标移动
    /// </summary>
    /// <param name="posY"></param>
    public void MoveY(float posY)
    {
        Clean();
        if (posY < 0)
        {
            posY = 0;
        }
        else if (posY > ViewHeightDis)
        {
            posY = ViewHeightDis;
        }
        _ltDescrMove = LeanTween.moveY(content, posY, MoveTime);
    }

    /// <summary>
    /// 清理(动画与惯性)
    /// </summary>
	public void Clean()
    {
        isInertia = false;
        if (_ltDescrHorzontal != null)
        {
            _ltDescrHorzontal.LTRemove();
            _ltDescrHorzontal = null;
        }
        if (_ltDescrVertical != null)
        {
            _ltDescrVertical.LTRemove();
            _ltDescrVertical = null;
        }
        if (_ltDescrMove != null)
        {
            _ltDescrMove.LTRemove();
            _ltDescrMove = null;
        }
    }


    #region 无限循环滚动


    public LuaTable LuaModule
    {
        get
        {
            _l = LuaHelper.GetLuaComponent(gameObject, "LoopScroll");
            return _l;
        }
    }

    /// <summary>
    /// 设置Item行or列数最大值
    /// </summary>
    /// <param name="row"></param>
    public void SetMaxRow(int row)
    {
        loopMax = row;
        useLoop = loopMax > loopRow;
    }

    public int GetLoopIndex()
    {
        return _loopIndex;
    }

    public void SetLoopIndex(int index)
    {
        _loopIndex = index;
    }

    /// <summary>
    /// 初始化循环
    /// </summary>
    /// <param name="tfs"></param>
    public virtual void InitLoop(RectTransform[] tfs)
    {
        _loopIndex = 0;
        _tfLoops = new List<RectTransform>(tfs);
        for (int i = 0; i < _tfLoops.Count; i++)
        {
            _tfLoops[i].anchoredPosition = new Vector2((i % loopCol) * cell_x, -((i / loopCol) * cell_y + topDistance));
            _tfLoops[i].gameObject.name = "item" + (i + 1);
        }

        ContentPosition = Vector2.zero;
    }

    /// <summary>
    /// 重置循环坐标(上下互换, )
    /// </summary>
    public virtual void ResetLoopPosition()
    {
        if (!useLoop) return;
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (horzontal)
        {
            //水平用不到目前.
        }

        if (vertical)
        {
            if (_loopIndex + loopRow < loopMax && m_ViewBounds.min.y - min.y < (loopMax - _loopIndex - loopRow + 1) * cell_y)
            {
                VerticalUp();
                _loopIndex++;
                //call back
                if (onLoopFront != null && m_IsEnable)
                {
                    onLoopFront.Invoke(_loopIndex + loopRow);
                }
            }
            else if (_loopIndex > 0 && max.y - m_ViewBounds.max.y < (_loopIndex + 1) * cell_y)
            {
                VerticalDown();
                //call back
                if (onLoopBack != null && m_IsEnable)
                {
                    onLoopBack.Invoke(_loopIndex);
                }
                _loopIndex--;
            }
        }
    }

    /// <summary>
    /// 向上拖拽(Item下移)
    /// </summary>
    protected virtual void VerticalUp()
    {
        for (int i = 0; i < loopCol; i++)
        {
            RectTransform rt = _tfLoops[0];
            rt.anchoredPosition = new Vector2(i * cell_x, -((_loopIndex + loopRow) * cell_y + topDistance));
            rt.gameObject.name = "Item" + ((_loopIndex + loopRow) * loopCol + i + 1);
            _tfLoops.RemoveAt(0);
            _tfLoops.Add(rt);
        }
    }

    /// <summary>
    /// 向下拖拽(Item上移)
    /// </summary>
    protected virtual void VerticalDown()
    {
        for (int i = 0; i < loopCol; i++)
        {
            RectTransform rt = _tfLoops[_tfLoops.Count - 1];
            rt.anchoredPosition = new Vector2((loopCol - i - 1) * cell_x, -((_loopIndex - 1) * cell_y + topDistance));
            rt.gameObject.name = "Item" + (_loopIndex * loopCol + i);
            _tfLoops.RemoveAt(_tfLoops.Count - 1);
            _tfLoops.Insert(0, rt);
        }
    }

    /// <summary>
    /// 相当于ResetPosition
    /// </summary>
    /// <returns>动画移动对象，用于设置回调</returns>
    public virtual LTDescr ScrollToStart()
    {
        var lt = LeanTween.moveY(content, 0f, 0.2f);
        return lt;
    }

    /// <summary>
    /// 修正item位置以及高度
    /// </summary>
    /// <param name="rt"></param>
    public virtual void FixItemsPosAndHeight(RectTransform rt)
    {

    }

    public virtual void PostInitLoop(RectTransform[] tfs)
    {

    }

    public virtual void AddNewItem(RectTransform newItem, RectTransform[] items, bool isHistoryMsg)
    {

    }

    private float _contentHeight;

    #endregion

    private bool isInertia;

    void LateUpdate()
    {
        try
        {

            if (!m_IsEnable) return;

            if (isInertia)
            {
                if (_nowInertiaSpeed == OutInertiaSpeed)
                {
                    TweenBack();
                    isInertia = false;
                    return;
                }
                firstPoint = Vector2.Lerp(firstPoint, InertiaDestPoint, _nowInertiaSpeed * Time.deltaTime);
                Vector2 moveOffset = firstPoint - lastPoint;
                bool border = MoveDistance(moveOffset);
                lastPoint = firstPoint;
                float magnitudeDis = 1;
                if (onSlideEnd != null)
                {
                    magnitudeDis = 4;
                }
                if ((firstPoint - InertiaDestPoint).magnitude < magnitudeDis || border)
                {
                    TweenBack();
                    isInertia = false;
                    if (onSlideEnd != null)
                    {
                        onSlideEnd.Invoke();
                    }
                }
            }
            else
            {
                if (ContentHeight < _contentHeight)
                {
                    Clean();
                    TweenBack();
                }
                _contentHeight = ContentHeight;
            }
        }
        catch (Exception e)
        {
            // ignored
        }
    }
}
